package com.koron.util;


import org.springframework.util.Assert;

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
	
	private static String[] MONTHS = {"January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};

	private static String[] parsePatterns = { "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
			"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM", "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss",
			"yyyy.MM.dd HH:mm", "yyyy.MM" };
	
	private static final String[][] WEEK = {{"MONDAY", "一"}, {"TUESDAY", "二"}, {"WEDNESDAY", "三"}, {"THURSDAY", "四"}, {"FRIDAY", "五"}, {"SATURDAY", "六"}, {"SUNDAY", "日"}};

	public static String monthUS(int index) {
		return MONTHS[index];
	}

	public static Date getDate() {
		return new Date();
	}

	public static final ThreadLocal<Date> date = new ThreadLocal<Date>() {
		protected Date initialValue() {
			return new Date();
		}
	};

	public static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
		protected DateFormat initialValue() {
			return new SimpleDateFormat("yyyy-MM-dd");
		}
	};

	public static int getYear() {
		Calendar calendar = Calendar.getInstance();
		return calendar.get(Calendar.YEAR);
	}

	public static int getMonth() {
		Calendar calendar = Calendar.getInstance();
		return calendar.get(Calendar.MONTH);
	}

	public static int getDay() {
		Calendar calendar = Calendar.getInstance();
		return calendar.get(Calendar.DAY_OF_MONTH);
	}

	public static String parseDate(Date date, String pattern) {
		Assert.notNull(date, "date must not be null");
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		return sdf.format(date);
	}

	public static Date parseDate(String date) {
		Assert.notNull(date, "date must not be null");
		try {
			return parseDate(date, parsePatterns);
		} catch (ParseException e) {
			throw new RuntimeException(e);
		}
	}
	
    public static String getWeek() {
    	LocalDate date = LocalDate.now();
    	String week = String.valueOf(date.getDayOfWeek());
    	for(int i = 0; i < WEEK.length; i++) {
    		if(Objects.equals(week, WEEK[i][0])) {
    			return "星期" + WEEK[i][1];
    		}
    	}
    	return week;
    }
    
    /**
     * 天数间隔
     * @param beginDate
     * @param endDate
     * @return
     */
    public static int betweenHours(Date beginDate, Date endDate) {
    	return (int) Math.abs(ChronoUnit.HOURS.between(beginDate.toInstant(), endDate.toInstant()));
    }
    
    /**
     * 天数间隔
     * @param beginDate
     * @param endDate
     * @return
     */
    public static int betweenDays(Date beginDate, Date endDate) {
    	LocalDate blocal = toLocalDate(beginDate);
    	LocalDate elocal = toLocalDate(endDate);
    	return (int) Math.abs(ChronoUnit.DAYS.between(blocal, elocal));
    }
    
    public static int betweenDays2(Date beginDate, Date endDate) {
    	LocalDate blocal = toLocalDate(beginDate);
    	LocalDate elocal = toLocalDate(endDate);
    	return (int) ChronoUnit.DAYS.between(blocal, elocal);
    }
    
    /**
     * 天数间隔
     * @param beginDate
     * @param endDate
     * @return
     * @throws ParseException 
     */
    public static int betweenDays(String beginDate, String endDate) throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Date sdate = df.parse(beginDate);
		Date eDate = df.parse(endDate);
		return betweenDays(sdate, eDate);
    }
    
    public static int betweenDays2(String beginDate, String endDate) throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Date sdate = df.parse(beginDate);
		Date eDate = df.parse(endDate);
		return betweenDays2(sdate, eDate);
    }
    
    /**
     * 月份间隔
     * @param beginDate
     * @param endDate
     * @return
     */
    public static int betweenMonths(Date beginDate, Date endDate) {
    	LocalDate blocal = toLocalDate(beginDate);
    	LocalDate elocal = toLocalDate(endDate);
    	return (int) Math.abs(ChronoUnit.MONTHS.between(blocal, elocal));
    }
    
    /**
     * 月份间隔
     * @param beginDate
     * @param endDate
     * @return
     */
    public static int betweenMonths(String beginDate, String endDate) throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Date sdate = df.parse(beginDate);
		Date eDate = df.parse(endDate);
		return betweenMonths(sdate, eDate);
    }
    
    /**
     * 年份间隔
     * @param beginDate
     * @param endDate
     * @return
     */
    public static int betweenYears(Date beginDate, Date endDate) {
    	LocalDate blocal = toLocalDate(beginDate);
    	LocalDate elocal = toLocalDate(endDate);
    	return (int) Math.abs(ChronoUnit.YEARS.between(blocal, elocal));
    }
    
    public static LocalDate toLocalDate(Date date) {
    	Instant instant = date.toInstant();
    	ZoneId zone = ZoneId.systemDefault();
    	LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
    	return localDateTime.toLocalDate();
    }

	public static int getMonthId() {
		LocalDate date = LocalDate.now();
		String monthId = date.format(DateTimeFormatter.ofPattern("yyyyMM"));
		return Integer.parseInt(monthId);
	}
	
	public static int getMonthId(long monthsToSubtract) {
		LocalDate date = LocalDate.now();
		String monthId = date.plusMonths(monthsToSubtract)
				.format(DateTimeFormatter.ofPattern("yyyyMM"));
		return Integer.parseInt(monthId);
	}
	
	public static int getMonthId(int monthId, long monthsToSubtract) {
		String text = String.valueOf(monthId).substring(0, 4) + "-" + String.valueOf(monthId).substring(4, 6) + "-01";
		LocalDate date = LocalDate.parse(text);
		String month = date.plusMonths(monthsToSubtract)
				.format(DateTimeFormatter.ofPattern("yyyyMM"));
		return Integer.parseInt(month);
	}

	public static String getDayOfNextMonth(String strDate, int interval, int day) throws ParseException {
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		Date date = df.parse(strDate);
		Calendar calendar = Calendar.getInstance();
		calendar.setTime (date);
		calendar.set(Calendar.DAY_OF_MONTH, day);
		calendar.add(Calendar.MONTH, interval);
		return df.format(calendar.getTime());
	}

	/**
	 * 如果是同一天，将前端传来的到日的时间，转换成到秒的时间
	 * 2022-07-13,2022-07-13-->2022-07-13 00:00:00,2022-07-13 23:59:59
	 *
	 * @param startTime
	 * @param endTime
	 */
	public static void formatDateToDateTime(String startTime, String endTime) {
    	if (startTime.equals(endTime)) {
			String start = startTime.substring(0, 9);
			startTime = start + " 00:00:00";
			String end = endTime.substring(0, 9);
			endTime = end + " 23:59:59";
		}
	}

	/**
	 * 重叠
	 *
	 * @param startDate1 开始日期1
	 * @param endDate1   结束日期1
	 * @param startDate2 开始日期2
	 * @param endDate2   结束日期2
	 * @param isStrict   很严格
	 * @return boolean
	 */
	public static boolean isOverlap(LocalDateTime startDate1, LocalDateTime endDate1, LocalDateTime startDate2, LocalDateTime endDate2, boolean isStrict) {
		if (endDate1.isBefore(startDate1)) {

			return false;
		}
		if (endDate2.isBefore(startDate2)) {
			return false;
		}
		if (isStrict) {
			if (!(endDate1.isBefore(startDate2) || startDate1 .isAfter(endDate2) )) {
				return true;
			}
		} else {//startDate1 >= endDate2
			if (!((endDate1.isBefore(startDate2) || endDate1.isEqual(startDate2)) ||(startDate1.isAfter(endDate2)||startDate1.isEqual(endDate2)) )) {
				return true;
			}
		}
		return false;
	}


	/**
	 * 获取交叉点
	 *
	 * @param startDate1 开始日期1
	 * @param endDate1   结束日期1
	 * @param startDate2 开始日期2
	 * @param endDate2   结束日期2
	 * @return {@link Map}<{@link LocalDateTime},{@link LocalDateTime}>
	 */
	public static Map<LocalDateTime,LocalDateTime> getIntersections(LocalDateTime startDate1, LocalDateTime endDate1, LocalDateTime startDate2, LocalDateTime endDate2){
		try {
			Map<LocalDateTime,LocalDateTime> result=new HashMap<>(1);
			boolean overlap = isOverlap(startDate1, endDate1, startDate2, endDate2, true);
			if (!overlap){//无交集
				return result;
			}
			List<LocalDateTime> sortList= Arrays.asList(startDate1,endDate1,startDate2,endDate2);
			sortList=sortList.stream().sorted().collect(Collectors.toList());
			//获取交集区间
			if (!sortList.get(1).isEqual(sortList.get(2)))
			result.put(sortList.get(1),sortList.get(2));
			return result;
		}catch (Exception e){

			throw new RuntimeException("获取时间段交集失败:"+e.getMessage());
		}



	}

	public static List<Integer> monthsWithinTimePeriod (LocalDateTime startDate1, LocalDateTime endDate1){
		if (startDate1.isAfter(endDate1)){
			throw new RuntimeException("起始日期不能大于结束日期");
		}
		List<Integer> list=new ArrayList<>();
		Month startDate1Month = startDate1.getMonth();
		Month endDate1Month = endDate1.getMonth();
		int a=endDate1Month.getValue()-startDate1Month.getValue();

		int value = startDate1Month.getValue();
		for (int i = 0; i <= a; i++) {
			list.add(value);
			value++;
		}


		return list;

	}
	
	public static void main(String[] args) throws ParseException {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		System.out.println(betweenHours(sdf.parse("2019-09-06 12:09:10"), sdf.parse("2019-09-06 12:10:15")));;
		System.out.println(Instant.now());
	}

	/**
	 * 获得指定时间格式的Date时间
	 * @author wangzhe@piesat.cn
	 * @date 2018年7月21日
	 * @param time 时间字符串
	 * @param plan 时间格式
	 * @return 时间
	 */
	public static Date getDateByString(String time,String plan){
		Long times = getLongTimeByString(time, plan);
		return  new Date(times);
	}

	/**
	 * 获得指定时间格式的时间
	 * @author wangzhe@piesat.cn
	 * @date 2018年7月21日
	 * @param time 时间字符串
	 * @param plan 时间格式
	 * @return 时间
	 */
	public static String getStringDateByString(Date time,String plan){
		DateFormat format = new SimpleDateFormat(plan);
		return format.format(time);
	}

	/**
	 * 获得指定时间格式的毫秒值
	 * @author wangzhe@piesat.cn
	 * @date 2018年7月17日
	 * @param time 时间字符串
	 * @param plan 时间格式
	 * @return 毫秒值
	 */
	public static Long getLongTimeByString(String time,String plan){
		DateFormat format = new SimpleDateFormat(plan);
		Long result = null;
		try {
			result = format.parse(time).getTime();
		} catch (ParseException e) {
			e.printStackTrace();
		}
		return  result;
	}

}